package com.young.weixin.web;

import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.young.common.util.AESUtil;
import com.young.common.util.CommonUtil;
import com.young.common.util.StringUtils;
import com.young.weixin.model.WeixinMessageRequest;
import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 对接微信的接口
 * @author wangjiyu@imdada.cn
 * @create 2019/5/5
 */
@Controller
@RequestMapping("/weixin/api")
public class WeixinApiController {

    private static final Logger logger = LoggerFactory.getLogger(WeixinApiController.class);

    /**
     * 微信API
     * @param app
     * @param request
     * @return
     */
    @RequestMapping(value = "/{app}/message", method = RequestMethod.GET)
    @ResponseBody
    public Object baseConfig(@PathVariable("app")String app, WeixinMessageRequest weixinMessageRequest, HttpServletRequest request) {
        String token = "imrookie";

        logger.info("[微信API] 接收到微信公众号应用[{}]的消息,消息内容={}", app, weixinMessageRequest);
        if (!this.checkParamForGet(weixinMessageRequest)) {
            logger.error("[微信API] 参数校验失败,返回失败");
            return "param error";
        }
        //获取经排序后的字符串
        String verifyStr = this.buildParamSortStr(token, weixinMessageRequest.getTimestamp(), weixinMessageRequest.getNonce());
        logger.info("[微信API] 组织加密参数verifyStr={}", verifyStr);
        //sha1加密
        String verifyStrSha = DigestUtils.sha1Hex(verifyStr);
        logger.info("[微信API] 参数加密结果verifyStrSha={}", verifyStrSha);
        //校验
        if (!verifyStrSha.equals(weixinMessageRequest.getSignature())) {
            logger.error("[微信API] 加密结果与入参不一致,安全校验未通过,返回失败");
            //校验失败, 阻断
            return "error";
        }
        //成功则返回入参中的随机字符串
        return weixinMessageRequest.getEchostr();
    }

    @RequestMapping(value = "/{app}/message", method = RequestMethod.POST)
    @ResponseBody
    public Object baseConfig2(@PathVariable("app")String app, WeixinMessageRequest weixinMessageRequest, HttpServletRequest request) throws IOException {
        String token = "imrookie";
        String aesKey = "V0HdQ1ZdCOE5GP7gQLfXP5Hetnut3tgLNMFDFv07Qbb";
        String appId = "wxdee216b1969ea9b6";

        logger.info("[微信API] 接收到微信公众号应用[{}]的消息,消息内容={}", app, weixinMessageRequest);
        logger.info("参数===={}", CommonUtil.getParameterFromRequest(request));
        logger.info("请求方式===={}", request.getContentType());

        InputStream is = request.getInputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = is.read(bytes)) > -1) {
            byteArrayOutputStream.write(bytes, 0, len);
        }
        byte[] body = byteArrayOutputStream.toByteArray();
        String xml = new String(body, "UTF-8");
        logger.info("body数据=={}", xml);

        //解密消息内容
        try {
            Map<String, String> map = getParamAsMap(token, aesKey, appId, weixinMessageRequest, xml);
            logger.info("解密后数据为:{}", map);
        } catch (Exception e) {
            logger.error("发生异常:", e);
            return "success";
        }

        //回复消息
        String txt = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content></xml>";

        //成功则返回入参中的随机字符串
        return weixinMessageRequest.getEchostr();
    }

    public static void main(String[] args) throws Exception {
        //System.out.println(AESUtil.decript("515e860c862fb4b0148ee52a5c3331d65fc2c924", "V0HdQ1ZdCOE5GP7gQLfXP5Hetnut3tgLNMFDFv07Qbb"));
        //System.out.println(DigestUtils.sha1Hex(buildParamSortStr("imrookie", "1557047210", "1950504262")));
        String s = "<xml><ToUserName><![CDATA[gh_b92f71141c77]]></ToUserName><Encrypt><![CDATA[IWWRmeYUPc6uoyMuCdYPQjeJIyCjbj/hwn13UtsrrXECroGduIlJI20MGCE6GHTPwZSMHpz6yKffe5ukSRVqNWhmB7+ucp4D20u+wafnrYmeHQXnCzYLcY9qqRmceB789t4dfoToYPgTVcSNNBid+S+jDTVOhWs7KDy6UhrascpsfjTsnaH2QY+r7iUPHO5UDWuh7rikjKTENpvU71fBp+hJkTVxujQqZMhMq/W43saMK4zlkUsru+8VdW5XD/9wNMaz4SwBt/BMlBUi5l73zvAxbBHhtsrC8sUHj+u8KlP7BbnTTxThAKzP3orAWf4eWrSDcbQ4lLrkUak6in7+Ff1F8TtcxiEUzNnyxYf4fCCB+DTuMFNI8xMyaTA5Nm0MMUPAS9Qg9kp1uucfNNLeb2NjWBN6WwvQRdkIM2+RH1A=]]></Encrypt></xml>";

        WXBizMsgCrypt pc = new WXBizMsgCrypt("imrookie", "V0HdQ1ZdCOE5GP7gQLfXP5Hetnut3tgLNMFDFv07Qbb", "wxdee216b1969ea9b6");
        String result2 = pc.decryptMsg("39e7fd1190227d3cd6326fbbeff4f59e9be05c6c", "1557050846", "523094646", s);
        System.out.println("解密后明文: " + result2);
        Map<String, String> map = xmlStrToMap(result2);
        System.out.println(map);
        //System.out.println(AESUtil.decript(map.get("Encrypt"), "V0HdQ1ZdCOE5GP7gQLfXP5Hetnut3tgLNMFDFv07Qbb"));
    }

    private Map<String, String> getParamAsMap(String token, String aesKey, String appId, WeixinMessageRequest weixinMessageRequest, String xml) throws Exception {
        WXBizMsgCrypt pc = new WXBizMsgCrypt(token, aesKey, appId);
        String result2 = pc.decryptMsg(weixinMessageRequest.getMsg_signature(), weixinMessageRequest.getTimestamp(), weixinMessageRequest.getNonce(), xml);
        System.out.println("解密后明文: " + result2);
        Map<String, String> map = xmlStrToMap(result2);
        return map;
    }

    private static Map<String,String> xmlStrToMap(String xmlStr) throws Exception{
        //返回值
        Map<String,String> resMap = new HashMap<String,String>();
        //将xml字符串解析为xml文档对象
        Document document = DocumentHelper.parseText(xmlStr);
        //获取xml文档对象的根节点元素
        Element root = document.getRootElement();
        //获取根节点下的所有子节点
        List<Element> list = root.elements();
        if(list != null && list.size() > 0){
            /*Element dataNode = list.get(0);//数据存在root节点下的第一个节点中
            list = dataNode.elements();*/
            //迭代节点信息
            for(Element e : list){
                String value = e.getText();//得到文本
                String key = e.getName();//得到节点名
                resMap.put(key, value);
            }
        }

        return resMap;
    }

    /**
     * 校验参数
     * @param weixinMessageRequest
     * @return
     */
    private boolean checkParamForGet(WeixinMessageRequest weixinMessageRequest) {
        if (weixinMessageRequest == null || StringUtils.isBlank(weixinMessageRequest.getSignature()) || StringUtils.isBlank(weixinMessageRequest.getTimestamp())
                || StringUtils.isBlank(weixinMessageRequest.getNonce()) || StringUtils.isBlank(weixinMessageRequest.getEchostr())) {
            return false;
        }
        return true;
    }

    /**
     * 构建校验参数
     * @param token
     * @param timestamp
     * @param nonce
     * @return
     */
    private static String buildParamSortStr(String token, String timestamp, String nonce) {
        String[] arr = {token, timestamp, nonce};
        Arrays.sort(arr);//排序
        StringBuilder sb = new StringBuilder();
        for (String str : arr) {
            sb.append(str);
        }
        return sb.toString();
    }
}
